package org.rsbot.script.methods;

import org.rsbot.script.wrappers.RSPlayer;

import java.awt.Color;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.rsbot.script.wrappers.RSVerifiable;

/**
 * Provides access to methods that can be used by RSBot scripts.
 */
public class Methods {

    /**
     * The logger instance
     */
    protected Logger log = Logger.getLogger(getClass().getName());
    /**
     * The instance of {@link java.util.Random} for random number generation.
     */
    protected java.util.Random random = new java.util.Random();
    /**
     * The singleton of Skills
     */
    protected Skills skills;
    /**
     * The singleton of Settings
     */
    protected Settings settings;
    /**
     * The singleton of Magic
     */
    protected Magic magic;
    /**
     * The singleton of Bank
     */
    protected Bank bank;
    /**
     * The singleton of Players
     */
    protected Players players;
    /**
     * The singleton of Store
     */
    protected Store store;
    /**
     * The singleton of GrandExchange
     */
    protected GrandExchange grandExchange;
    /**
     * The singletion of Hiscores
     */
    protected Hiscores hiscores;
    /**
     * The singleton of ClanChat
     */
    protected ClanChat clanChat;
    /**
     * The singleton of Camera
     */
    protected Camera camera;
    /**
     * The singleton of NPCs
     */
    protected NPCs npcs;
    /**
     * The singleton of GameScreen
     */
    protected Game game;
    /**
     * The singleton of Combat
     */
    protected Combat combat;
    /**
     * The singleton of Interfaces
     */
    protected Interfaces interfaces;
    /**
     * The singleton of Mouse
     */
    protected Mouse mouse;
    /**
     * The singleton of Keyboard
     */
    protected Keyboard keyboard;
    /**
     * The singleton of Menu
     */
    protected Menu menu;
    /**
     * The singleton of Tiles
     */
    protected Tiles tiles;
    /**
     * The singleton of Objects
     */
    protected Objects objects;
    /**
     * The singleton of Walking
     */
    protected Walking walking;
    /**
     * The singleton of Calculations
     */
    protected Calculations calc;
    /**
     * The singleton of Inventory
     */
    protected Inventory inventory;
    /**
     * The singleton of Equipment
     */
    protected Equipment equipment;
    /**
     * The singleton of GroundItems
     */
    protected GroundItems groundItems;
    /**
     * The singleton of Account
     */
    protected Account account;
    /**
     * The singleton of Summoning
     */
    protected Summoning summoning;
    /**
     * The singleton of Environment
     */
    protected Environment env;

    /**
     * For internal use only: initializes the
     * method providers.
     *
     * @param ctx The MethodContext.
     */
    public void init(MethodContext ctx) {
        this.skills = ctx.skills;
        this.settings = ctx.settings;
        this.magic = ctx.magic;
        this.bank = ctx.bank;
        this.players = ctx.players;
        this.store = ctx.store;
        this.grandExchange = ctx.grandExchange;
        this.hiscores = ctx.hiscores;
        this.clanChat = ctx.clanChat;
        this.camera = ctx.camera;
        this.npcs = ctx.npcs;
        this.game = ctx.game;
        this.combat = ctx.combat;
        this.interfaces = ctx.interfaces;
        this.mouse = ctx.mouse;
        this.keyboard = ctx.keyboard;
        this.menu = ctx.menu;
        this.tiles = ctx.tiles;
        this.objects = ctx.objects;
        this.walking = ctx.walking;
        this.calc = ctx.calc;
        this.inventory = ctx.inventory;
        this.equipment = ctx.equipment;
        this.groundItems = ctx.groundItems;
        this.account = ctx.account;
        this.summoning = ctx.summoning;
        this.env = ctx.env;
    }

    /**
     * Returns the current client's local player.
     *
     * @return The current client's <tt>RSPlayer</tt>.
     * @see Players#getMyPlayer()
     */
    public RSPlayer getMyPlayer() {
        return players.getMyPlayer();
    }

    /**
     * Returns a random integer with min as the inclusive
     * lower bound and max as the exclusive upper bound.
     *
     * @param min The inclusive lower bound.
     * @param max The exclusive upper bound.
     * @return Random integer min <= n < max.
     */
    public int random(int min, int max) {
        int n = Math.abs(max - min);
        return Math.min(min, max) + (n == 0 ? 0 : random.nextInt(n));
    }
/**
 *
 * @param v object to be verified
 * @return a flag for its existance => true if non null.
 */
    public boolean exists(RSVerifiable v) {
        return v != null;
    }

    /**
     * Returns a random double with min as the inclusive
     * lower bound and max as the exclusive upper bound.
     *
     * @param min The inclusive lower bound.
     * @param max The exclusive upper bound.
     * @return Random double min <= n < max.
     */
    public double random(double min, double max) {
        return Math.min(min, max) + random.nextDouble() * Math.abs(max - min);
    }

    /**
     * Pauses execution for a random amount of time between two values.
     *
     * @param minSleep The minimum time to sleep.
     * @param maxSleep The maximum time to sleep.
     * @see #sleep(int)
     * @see #random(int, int)
     */
    public void sleep(int minSleep, int maxSleep) {
        sleep(random(minSleep, maxSleep));
    }

    /**
     * Pauses execution for a given number of milliseconds.
     *
     * @param toSleep The time to sleep in milliseconds.
     */
    public void sleep(int toSleep) {
        try {
            long start = System.currentTimeMillis();
            Thread.sleep(toSleep);

            // Guarantee minimum sleep
            long now;
            while (start + toSleep > (now = System.currentTimeMillis())) {
                Thread.sleep(start + toSleep - now);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * Prints to the RSBot log.
     *
     * @param message Object to log.
     */
    public void log(Object message) {
        log.info(message.toString());
    }

    /**
     * Prints to the RSBot log with a font color
     *
     * @param color The color of the font
     * @param message Object to log
     * */
    public void log(Color color, Object message) {
        Object[] parameters = {color};
        log.log(Level.INFO, message.toString(), parameters);
    }
}
